﻿using Microsoft.Xna.Framework;
using JigLibX.Physics;
using Microsoft.Xna.Framework.Input;
using SolarWinds.Helpers;
using System;

namespace SolarWinds.Controllers
{
    /// <summary>
    /// The ShipController read input from input devices (like mouse, keyboard, gamepad ...) 
    /// to modidy the state of the ship.
    /// </summary>
    public class ShipController : GameComponent
    {
        public event EventHandler PrimaryFire;
        public event EventHandler SecondaryFire;

        private readonly ShipForceController mShipForceController;
        private float mNextPrimaryFireTime;
        private float mNextSecondaryFireTime;

        /// <summary>
        /// Creates an instance of the ShipController class
        /// </summary>
        /// <param name="game">The Game</param>
        /// <param name="body">The body of the ship actor</param>
        public ShipController(Game game, Body body) : 
            base(game)
        {
            mShipForceController = new ShipForceController(body);
        }       

        public override void Update(GameTime gameTime)
        {
            base.Update(gameTime);

            MouseState mouseState = Mouse.GetState();
#if !DEBUG            
            // correct mouse position
            if (mouseState.X < 0)
            {
                Mouse.SetPosition(0, mouseState.Y);
            }
            if (mouseState.Y < 0)
            {
                Mouse.SetPosition(mouseState.X, 0);
            }
            if (mouseState.X > Game.Window.ClientBounds.Width)
            {
                Mouse.SetPosition(Game.Window.ClientBounds.Width, mouseState.Y);
            }
            if (mouseState.Y > Game.Window.ClientBounds.Height)
            {
                Mouse.SetPosition(mouseState.X, Game.Window.ClientBounds.Height);
            }
#endif
            // use mouse to steer ship
            {
                var mousePosition = new Vector2(mouseState.X, mouseState.Y);                
                Vector3 oldPosition = mShipForceController.Body.Position;
                Vector3 newPosition = PickingHelper.GetPickedPosition(SolarWindsGame.Camera, mousePosition);

                Vector3 dist = (newPosition - oldPosition);
                
                mShipForceController.Force = dist * 1000; // TODO add a constant 'Agility' to the ship model 

                // TODO apply some toque - think about mBody.SetBodyInvInertia(0.0f, 0.0f, 0.0f) in ship class, 
                // which inhibits rotation
                // float angle = (float)Math.Acos(Vector3.Dot(Vector3.Normalize(dist), Vector3.UnitZ));
                // mShipForceController.Torque = Vector3.UnitY * angle * 1000;
            }

            // emit primary fire
            if (mouseState.LeftButton == ButtonState.Pressed)
            {
                mNextPrimaryFireTime -= (float)gameTime.ElapsedGameTime.TotalMilliseconds;
                if (mNextPrimaryFireTime < 0.0f)
                {
                    if (PrimaryFire != null)
                    {
                        PrimaryFire(this, EventArgs.Empty);
                    }

                    mNextPrimaryFireTime = 300.0f; // TODO read parameter 'PrimaryFirerate' from ship model
                }
            }

            // emit secondary fire
            if (mouseState.RightButton == ButtonState.Pressed)
            {
                mNextSecondaryFireTime -= (float)gameTime.ElapsedGameTime.TotalMilliseconds;
                if (mNextSecondaryFireTime < 0.0f)
                {
                    if (SecondaryFire != null)
                    {
                        SecondaryFire(this, EventArgs.Empty);
                    }

                    mNextSecondaryFireTime = 2000.0f; // TODO read parameter 'PrimaryFirerate' from ship model
                }
            }
        }
    }

    /// <summary>
    /// This class forms a part of the main ShipController.
    /// It adds external forces to the ShipActor that controls 
    /// the ShipShape.
    /// </summary>
    class ShipForceController : Controller
    {
        public Vector3 Force;
        public Vector3 Torque;

        private readonly Body mBody;
        public Body Body
        {
            get { return mBody; }
        }

        public ShipForceController(Body body)
        {
            EnableController();
            PhysicsSystem.CurrentPhysicsSystem.AddController(this);
            mBody = body;
        }

        public override void UpdateController(float dt)
        {
            mBody.ClearForces();
            mBody.ClearVelChanged();
            if (Force != Vector3.Zero)
            {
                Vector3 worldForce = Force - mBody.Mass * mBody.Velocity;
                mBody.AddWorldForce(worldForce);

                if (!mBody.IsActive) mBody.SetActive();
            }
            if (Torque != Vector3.Zero)
            {
                Vector3 worldTorque = Torque - mBody.Mass * mBody.AngularVelocity;
                mBody.AddWorldForce(worldTorque);

                if (!mBody.IsActive) mBody.SetActive();
            }
        }
    }


}
